﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Windows.Forms;
using EnvDTE;
using EnvDTE80;
using VSLangProj80;

namespace Lexware.Tools.ProjectPropertyOverview
{
    /// <summary>
    /// 
    /// </summary>
    internal class ConfigurationPropertiesManager
    {
        #region Fields

        private const string _csProjectFileExtension = ".csproj";

        /// <summary>
        /// 
        /// </summary>
        private readonly ProjectConfigurationPropertiesCollection _propertiesCollection;

        /// <summary>
        /// 
        /// </summary>
        private DTE2 _applicationObject;

        #endregion

        #region Constructors

        /// <summary>
        /// Initializes a new instance of the <see cref="ConfigurationPropertiesManager"/> class.
        /// </summary>
        public ConfigurationPropertiesManager()
        {
            _propertiesCollection = new ProjectConfigurationPropertiesCollection();
        }

        #endregion

        #region Properties

        /// <summary>
        /// Sets the application object.
        /// </summary>
        /// <value>The application object.</value>
        public DTE2 ApplicationObject
        {
            set { _applicationObject = value; }
        }

        #endregion

        #region Public Methods

        /// <summary>
        /// Reads all project properties.
        /// </summary>
        public void ReadAllProjectProperties(BindingSource projectConfigurationPropertiesCollectionBindingSource)
        {
            if ((_applicationObject != null) && (_applicationObject.Solution != null))
            {
                // Walk through the projects of the solution and search for assembly references
                foreach (Project currentProject in _applicationObject.Solution.Projects)
                {
                    ReadProjectReferences(currentProject);
                }

                projectConfigurationPropertiesCollectionBindingSource.DataSource = _propertiesCollection;
            }
        }

        /// <summary>
        /// Reads all project properties.
        /// </summary>
        public void ReadAllProjectProperties(BindingSource projectConfigurationPropertiesCollectionBindingSource, Project deletedProject)
        {
            if ((_applicationObject != null) && (_applicationObject.Solution != null))
            {
                // Walk through the projects of the solution and search for assembly references
                foreach (Project currentProject in _applicationObject.Solution.Projects)
                {
                    if (currentProject != deletedProject)
                    {
                        ReadProjectReferences(currentProject);
                    }
                }

                projectConfigurationPropertiesCollectionBindingSource.DataSource = _propertiesCollection;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="index"></param>
        public void SetDefaultConfigurationProperties(int index)
        {
            _propertiesCollection[index].SetDefaultConfigurationProperties(ProjectProjectConfigurationConstants.PredefinedConfigurationProperties);
        }

        /// <summary>
        /// Sets the default configuration properties.
        /// </summary>
        /// <param name="configuration">The config.</param>
        public void SetDefaultConfigurationProperties(ProjectConfigurationProperties configuration)
        {
            configuration.SetDefaultConfigurationProperties(ProjectProjectConfigurationConstants.PredefinedConfigurationProperties);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="index"></param>
        /// <param name="project"></param>
        public void SetDefaultConfigurationPropertiesFromProjectFile(Int32[] index, Project project)
        {
            DefaultConfigurationPropertyList defaultPropertyCollection = LoadReferenceProject(project);

            if (defaultPropertyCollection.Count > 0)
            {
                foreach (int indx in index)
                {
                    List<DefaultConfigurationPropertyItem> defaultList =
                        defaultPropertyCollection.GetDefaultPropertiesForConfiguration(_propertiesCollection[indx].ConfigurationName);

                    _propertiesCollection[indx].SetDefaultConfigurationProperties(defaultList);
                }
            }
        }

        #endregion

        #region Private Methods

        /// <summary>
        /// Loads the reference project.
        /// </summary>
        /// <param name="project">The project.</param>
        /// <returns></returns>
        private DefaultConfigurationPropertyList LoadReferenceProject(Project project)
        {
            var defaultPropertyCollection = new DefaultConfigurationPropertyList();

            var configurationNames = (Array)project.ConfigurationManager.ConfigurationRowNames;

            IList<string> propertyNamesList = ProjectProjectConfigurationConstants.ConfigurationConstantNamesAsList;

            foreach (string configurationName in configurationNames)
            {
                foreach (ProjectConfigurationProperties configurationProperty in _propertiesCollection)
                {
                    if (configurationProperty.ConfigurationName == configurationName)
                    {
                        List<DefaultConfigurationPropertyItem> defaultConfigList = null;

                        foreach (Configuration configuration in project.ConfigurationManager.ConfigurationRow(configurationName))
                        {
                            Properties properties = configuration.Properties;

                            defaultConfigList = new List<DefaultConfigurationPropertyItem>(properties.Count);

                            foreach (Property property in properties)
                            {
                                if (propertyNamesList.Contains(property.Name))
                                {
                                    defaultConfigList.Add(new DefaultConfigurationPropertyItem(property.Name, property.Value));
                                }
                            }
                        }

                        defaultPropertyCollection.AddDefaultConfiguration(configurationName, defaultConfigList);
                    }
                }
            }

            return defaultPropertyCollection;
        }

        /// <summary>
        /// Reads the project references.
        /// </summary>
        /// <param name="currentProject">The current project.</param>        
        private void ReadProjectReferences(Project currentProject)
        {
            if (currentProject != null)
            {
                var visualStudioProject = currentProject.Object as VSProject2;

                // The current project can be a 'real' project, but it can also be a folder (see else if)
                if (visualStudioProject != null)
                {
                    string projectFullName = currentProject.FullName;

                    if (!string.IsNullOrEmpty(projectFullName))
                    {
                        FileInfo projectFileInfo = new FileInfo(projectFullName);

                        // If it is a csproj add it the the list view
                        if (projectFileInfo.Exists && (projectFileInfo.Extension == _csProjectFileExtension))
                        {

                            var configurationNames = (Array)currentProject.ConfigurationManager.ConfigurationRowNames;
                            foreach (string configurationName in configurationNames)
                            {
                                foreach (Configuration configuration in currentProject.ConfigurationManager.ConfigurationRow(configurationName))
                                {
                                    _propertiesCollection.Add(new ProjectConfigurationProperties(currentProject.Name, configuration, currentProject));
                                }
                            }
                        }
                    }
                }
                else if ((currentProject.ProjectItems != null) && (currentProject.ProjectItems.Count > 0))
                {
                    // Project Item Type  	 GUID
                    // Physical File         {6BB5F8EE-4483-11D3-8BCF-00C04F8EC28C}
                    // Physical Folder       {6BB5F8EF-4483-11D3-8BCF-00C04F8EC28C}
                    // Virtual Folder        {6BB5F8F0-4483-11D3-8BCF-00C04F8EC28C}
                    // Subproject            {EA6618E8-6E24-4528-94BE-6889FE16485C}

                    // The projects contains a sub folder -> search for projects in these folders
                    foreach (ProjectItem currentProjectItem in currentProject.ProjectItems)
                    {
                        if (currentProjectItem.SubProject != null)
                        {
                            ReadProjectReferences(currentProjectItem.SubProject);
                        }
                    }
                }
            }
        }

        #endregion
    }
}